vulkan: Only render minimal region
authorBenjamin Otte <otte@redhat.com>
Mon, 26 Dec 2016 23:18:52 +0000 (00:18 +0100)
committerBenjamin Otte <otte@redhat.com>
Mon, 26 Dec 2016 23:31:33 +0000 (00:31 +0100)
It's faster to render once for every rectangle in the clip region than
rendering the outline of the clip region.
Especially because this reduces the time necessary to build up the frame
data.

In widget-factory (where we have 3 rectangles), this leads to a 5x
speedup in the rendering time rendering alone.
Snapshotting time goes from 10ms to ~1ms, which is another huge
improvement.

gsk/gskvulkanrender.c
gsk/gskvulkanrenderer.c

index a2968cc11ebfcda69e85cd6953aa8758056c9ac4..12dac4d73f109ebfc362ddf334258abd517f6bcd 100644 (file)
@@ -26,7 +26,7 @@ struct _GskVulkanRender
   graphene_matrix_t mvp;
   int scale_factor;
   VkRect2D viewport;
-  VkRect2D scissor;
+  cairo_region_t *clip;
 
   GHashTable *framebuffers;
   GskVulkanCommandPool *command_pool;
@@ -49,32 +49,31 @@ struct _GskVulkanRender
 };
 
 static void
-gsk_vulkan_render_compute_mvp (GskVulkanRender       *self,
-                               const graphene_rect_t *rect)
+gsk_vulkan_render_setup (GskVulkanRender       *self,
+                         GskVulkanImage        *target,
+                         const graphene_rect_t *rect)
 {
   GdkWindow *window = gsk_renderer_get_window (self->renderer);
   graphene_matrix_t modelview, projection;
-  cairo_rectangle_int_t extents;
+
+  self->target = g_object_ref (target);
 
   if (rect)
     {
-      self->scissor = (VkRect2D) { { 0, 0 }, { rect->size.width, rect->size.height } };
       self->viewport = (VkRect2D) { { rect->origin.x, rect->origin.y }, { rect->size.width, rect->size.height } };
       self->scale_factor = 1;
+      self->clip = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
+                                                      0, 0,
+                                                      gsk_vulkan_image_get_width (target), gsk_vulkan_image_get_height (target)
+                                                  });
     }
   else
     {
-      cairo_region_get_extents (gdk_drawing_context_get_clip (gsk_renderer_get_drawing_context (self->renderer)),
-                                &extents);
-
       self->scale_factor = gsk_renderer_get_scale_factor (self->renderer);
       self->viewport.offset = (VkOffset2D) { 0, 0 };
       self->viewport.extent.width = gdk_window_get_width (window) * self->scale_factor;
       self->viewport.extent.height = gdk_window_get_height (window) * self->scale_factor;
-      self->scissor.offset.x = extents.x * self->scale_factor;
-      self->scissor.offset.y = extents.y * self->scale_factor;
-      self->scissor.extent.width = extents.width * self->scale_factor;
-      self->scissor.extent.height = extents.height * self->scale_factor;
+      self->clip = gdk_drawing_context_get_clip (gsk_renderer_get_drawing_context (self->renderer));
     }
 
   graphene_matrix_init_scale (&modelview, self->scale_factor, self->scale_factor, 1.0);
@@ -464,6 +463,7 @@ gsk_vulkan_render_draw (GskVulkanRender   *self,
   GskVulkanBuffer *buffer;
   VkCommandBuffer command_buffer;
   GSList *l;
+  guint i;
 
   gsk_vulkan_render_prepare_descriptor_sets (self, sampler);
 
@@ -483,36 +483,43 @@ gsk_vulkan_render_draw (GskVulkanRender   *self,
                       .maxDepth = 1
                     });
 
-  vkCmdSetScissor (command_buffer,
-                   0,
-                   1,
-                   &self->scissor);
-
-  vkCmdBeginRenderPass (command_buffer,
-                        &(VkRenderPassBeginInfo) {
-                            .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
-                            .renderPass = self->render_pass,
-                            .framebuffer = gsk_vulkan_render_get_framebuffer (self, self->target),
-                            .renderArea = { 
-                                { 0, 0 },
-                                {
-                                    gsk_vulkan_image_get_width (self->target),
-                                    gsk_vulkan_image_get_height (self->target)
+  for (i = 0; i < cairo_region_num_rectangles (self->clip); i++)
+    {
+      cairo_rectangle_int_t rect;
+
+      cairo_region_get_rectangle (self->clip, i, &rect);
+
+      vkCmdSetScissor (command_buffer,
+                       0,
+                       1,
+                       &(VkRect2D) {
+                           { rect.x * self->scale_factor, rect.y * self->scale_factor },
+                           { rect.width * self->scale_factor, rect.height * self->scale_factor }
+                       });
+
+      vkCmdBeginRenderPass (command_buffer,
+                            &(VkRenderPassBeginInfo) {
+                                .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+                                .renderPass = self->render_pass,
+                                .framebuffer = gsk_vulkan_render_get_framebuffer (self, self->target),
+                                .renderArea = { 
+                                    { rect.x * self->scale_factor, rect.y * self->scale_factor },
+                                    { rect.width * self->scale_factor, rect.height * self->scale_factor }
+                                },
+                                .clearValueCount = 1,
+                                .pClearValues = (VkClearValue [1]) {
+                                    { .color = { .float32 = { 0.f, 0.f, 0.f, 0.f } } }
                                 }
                             },
-                            .clearValueCount = 1,
-                            .pClearValues = (VkClearValue [1]) {
-                                { .color = { .float32 = { 0.f, 0.f, 0.f, 0.f } } }
-                            }
-                        },
-                        VK_SUBPASS_CONTENTS_INLINE);
+                            VK_SUBPASS_CONTENTS_INLINE);
 
-  for (l = self->render_passes; l; l = l->next)
-    {
-      gsk_vulkan_render_pass_draw (l->data, self, buffer, self->layout, command_buffer);
-    }
+      for (l = self->render_passes; l; l = l->next)
+        {
+          gsk_vulkan_render_pass_draw (l->data, self, buffer, self->layout, command_buffer);
+        }
 
-  vkCmdEndRenderPass (command_buffer);
+      vkCmdEndRenderPass (command_buffer);
+    }
 
   gsk_vulkan_command_pool_submit_buffer (self->command_pool, command_buffer, self->fence);
 
@@ -563,6 +570,7 @@ gsk_vulkan_render_cleanup (GskVulkanRender *self)
   g_slist_free_full (self->cleanup_images, g_object_unref);
   self->cleanup_images = NULL;
 
+  g_clear_pointer (&self->clip, cairo_region_destroy);
   g_clear_object (&self->target);
 }
 
@@ -631,9 +639,7 @@ gsk_vulkan_render_reset (GskVulkanRender       *self,
 {
   gsk_vulkan_render_cleanup (self);
 
-  self->target = g_object_ref (target);
-
-  gsk_vulkan_render_compute_mvp (self, rect);
+  gsk_vulkan_render_setup (self, target, rect);
 }
 
 GskRenderer *
index 747ed09c902a80e9a5021da123a522832e6fcbb8..4ae0f4deeefd0ba189b060e630829f93944e7ee9 100644 (file)
@@ -257,23 +257,11 @@ gsk_vulkan_renderer_begin_draw_frame (GskRenderer          *renderer,
                                       const cairo_region_t *region)
 {
   GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
-  cairo_region_t *whole_window;
   GdkDrawingContext *result;
-  GdkWindow *window;
-
-  window = gsk_renderer_get_window (renderer);
-  
-  whole_window = cairo_region_create_rectangle (&(GdkRectangle) {
-                                                    0, 0,
-                                                    gdk_window_get_width (window),
-                                                    gdk_window_get_height (window)
-                                                });
 
-  result = gdk_window_begin_draw_frame (window,
+  result = gdk_window_begin_draw_frame (gsk_renderer_get_window (renderer),
                                         GDK_DRAW_CONTEXT (self->vulkan),
-                                        whole_window);
-
-  cairo_region_destroy (whole_window);
+                                        region);
 
   return result;
 }